home *** CD-ROM | disk | FTP | other *** search
Text File | 2008-03-14 | 46.8 KB | 1,306 lines |
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the License.
- *
- * The Original Code is the Autocomplete Manager extension.
- *
- * The Initial Developer of the Original Code is
- * Nikitas Liogkas <nikitas@acm.org>.
- * Portions created by the Initial Developer are Copyright (C) 2005-2008
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s): James Ravn, Heiwad Osman
- * Version: 2.3
- *
- * ***** END LICENSE BLOCK ***** */
-
- // acpopup.js
- // implements the location bar and popup functionality; retrieves all
- // matching entries from the filterer and displays them in a custom popup
- // that contains a tree with the suggestions ordered by the desired criterion
-
- const acm_atomService = Components.classes["@mozilla.org/atom-service;1"]
- .getService(Components.interfaces.nsIAtomService);
-
- const ACM_LOAD_TAB_IN_BACKGROUND = "browser.tabs.loadInBackground";
-
- // popup parameters
- var acm_popupExists = false;
- var acm_preventPopup = false; // hack to prevent re-display of popup when pressing Shift+Del
- var acm_disablePopup = false; // temporarily disable popup at user's will
- var acm_disableInlining = false; // prevent inlining after a Del or a Backspace
- var acm_typedPrefix = null; // the prefix the user has typed in so far
- var acm_tooltip = null; // the tooltip to display on a popup re-sorting
- var acm_tooltipTimeout = null; // the id of the tooltip timeout call
- var acm_shiftPressed = false;
-
- var acm_ontextenteredHandler = null; // the original handler code that we override
- var acm_loadParams = null; // the parameters to pass to handleURLBarCommand()
-
- // suggestion list caching
- var acm_lastPrefix = null; // the prefix the user had typed in last time we looked
- // "" denotes blank search string / history dropdown
- var acm_lastResults = null; // cached suggestion result array for this browser window
-
- // common protocols and prefixes to ignore
- const acm_commonProtocol = /^(http|https|ftp):\/\//i;
- const acm_commonPrefix = /^(www|ftp)\./i;
-
- // regular expression for non letters, digits, and spaces
- const acm_nonLetterDigitSpace = /[^a-z0-9\s]+/gi;
-
- // cached value of the ACM_BOOKMARKS_FIRST preference for better performance when sorting
- var acm_bookfirst;
-
- // hint to alphaURLCompareFun to check bookmarks-first ordering when called directly,
- // rather than from another sorting function
- var acm_checkBookFirst = false;
-
- // popup tree
- var acm_treePopup = null;
- var acm_popupTreePos = null;
- var acm_maxrows; // number of visible rows in the popup tree
- var acm_rowHeight = 0; // the height of a single row in the popup tree
- var acm_suggestions; // array of AutocompleteCandidate's currently displayed on the popup
-
- //var browser_version_index = navigator.userAgent.indexOf("Firefox") + 8;
- //var browser_version = navigator.userAgent.substring(browser_version_index,
- // navigator.userAgent.length);
- //if (browser_version.charAt(0) !== '1')
-
- // the view for the popup tree
- var acm_treePopupView =
- {
- rowCount: 0,
- getCellText: function(row, column)
- {
- var text = "";
-
- // bookmarks separator
- if (row === acm_matching_bookmarks && acm_matching_bookmarks > 0
- && acm_matching_bookmarks !== acm_suggestions.length)
- return text;
-
- const entry = acm_suggestions[row];
- var date = "[" + acm_micros2date(entry.last_visit) + "]";
-
- if (column.id === "colURL")
- text = entry.URL;
- else if (column.id === "coltitle")
- text = entry.title;
- else if (column.id === "colsource")
- text = date;
-
- return text;
- },
- // returns the icon URL to display
- getImageSrc: function(row, column)
- {
- // bookmarks separator
- if (row === acm_matching_bookmarks && acm_matching_bookmarks > 0
- && acm_matching_bookmarks !== acm_suggestions.length)
- return null;
-
- const entry = acm_suggestions[row];
- if (column.index === 0) {
- var iconURL = entry.icon;
- if (iconURL !== "") // URL-specific favicon
- return iconURL;
- else { // generic theme favicon
-
- return acm_defaultIcon;
- }
- }
- else
- return null;
- },
- getRowProperties: function(row, props){ },
- getCellProperties: function(row, column, properties)
- {
- // bookmarks separator
- if (row === acm_matching_bookmarks && acm_matching_bookmarks > 0
- && acm_matching_bookmarks !== acm_suggestions.length)
- return;
-
- // dim the text for all but the first column
- if (column.index !== 0)
- properties.AppendElement(acm_atomService.getAtom("dim"));
-
- // make the bookmark matches italic
- if (acm_suggestions[row].source === ACM_SOURCE_BOOKMARKS)
- properties.AppendElement(acm_atomService.getAtom("italic"));
-
- // bold the column where the match occurred
- if (acm_getPreference(ACM_BOLD_MATCHING)) {
- var field = acm_suggestions[row].matched_against.substr(2);
- if (column.id === "col" + field)
- properties.AppendElement(acm_atomService.getAtom("bold"));
- }
- },
- getColumnProperties: function(colid, col, props) { },
- isContainer: function(index) { return false; },
- isEditable: function(row, column) { return false; },
- // draw separator after matching bookmarks, if they are being displayed at the top
- // NOTE: the sanity checks are done elsewhere for better performance, and
- // an extra stub entry is added to acm_suggestions[] after sorting, just for the separator
- isSeparator: function(row) {
- // do not insert bookmarks separator if either no bookmarks or history entries matched
- if (row === acm_matching_bookmarks && acm_matching_bookmarks > 0
- && acm_matching_bookmarks !== acm_suggestions.length)
- return true;
- else
- return false;
- },
- isSorted: function(row) { return false; },
- setCellText: function(row, column, value) { },
- setTree: function() { }
- };
-
- // timer to defer matching when typing rapidly in the location bar
- var acm_typingTimer = Components.classes["@mozilla.org/timer;1"]
- .createInstance(Components.interfaces.nsITimer);
- const acm_timerDelay = 250; // in milliseconds; 50 is the Firefox default
- var acm_timerObserver =
- {
- observe: function(subject, topic, data) {
- // invoke a bit later to (maybe) avoid freezing user's typing on the location bar
- //setTimeout(acm_handleTyping, 30);
- acm_handleTyping();
- }
- };
-
- // handles a string typed on the location bar by producing the corresponding popup
- function acm_handleTyping()
- {
- // check for difference in common protocols, e.g. transition from 'http:/' to 'http://'
- // NOTE: do not use indexOf() for regular expressions
- if (acm_lastPrefix !== null
- && acm_lastPrefix.search(acm_commonProtocol) === -1
- && acm_typedPrefix.search(acm_commonProtocol) !== -1)
- acm_lastPrefix = null; // invalidate window cache
-
- // check for difference in common prefixes, e.g. transition from 'www' to 'www.'
- if (acm_lastPrefix !== null
- && acm_lastPrefix.search(acm_commonPrefix) === -1
- && acm_typedPrefix.search(acm_commonPrefix) !== -1)
- acm_lastPrefix = null; // invalidate window cache
-
- // for the blank search string, Firefox uses the order by which entries were entered
- // in the history file; we use most recently visited.
- if (acm_typedPrefix === "") {
- // set the number of matching bookmarks for placing the bookmarks separator on the popup
- if (acm_getPreference(ACM_MATCH_BOOKMARKS) && acm_getPreference(ACM_BOOKMARKS_FIRST))
- acm_matching_bookmarks = acm_Aggregator.singleton().bookmarks.length;
- else
- acm_matching_bookmarks = -1;
- acm_buildPopup(acm_Aggregator.singleton().allCandidates.sort(acm_mruCompareFun));
- }
-
- // check if we can reuse the last computed results; no need to re-sort
- else if (acm_lastPrefix !== null && acm_lastPrefix !== ""
- && acm_typedPrefix.length >= acm_lastPrefix.length
- && acm_typedPrefix.substring(0, acm_lastPrefix.length) === acm_lastPrefix) {
- // remove bookmarks separator, as it will be re-inserted by acm_buildPopup()
- if (acm_matching_bookmarks > 0 && acm_matching_bookmarks !== acm_suggestions.length)
- acm_lastResults.splice(acm_matching_bookmarks, 1);
- acm_lastResults = acm_getFilteredCandidates(acm_lastResults);
- acm_buildPopup(acm_lastResults);
- }
-
- // perform the matching from scratch
- else {
- acm_lastResults = acm_getSortedSuggestionList(null);
- acm_buildPopup(acm_lastResults);
- }
-
- // update prefix
- acm_lastPrefix = acm_typedPrefix;
-
- // complete and highlight best match inline, it is matched at the beginning of URL or title
- if (acm_getPreference(ACM_INLINE) && acm_popupExists
- && acm_suggestions[0].matched_against.indexOf("b-") === 0 && !acm_disableInlining) {
- // strip common protocols and prefixes, unless they were typed in
- var field = acm_suggestions[0].matched_against.substr(2);
- var new_value = acm_suggestions[0][field];
- if (field === "URL") {
- if (acm_typedPrefix.search(acm_commonProtocol) === -1)
- new_value = new_value.replace(acm_commonProtocol, "");
- if (acm_typedPrefix.search(acm_commonPrefix) === -1)
- new_value = new_value.replace(acm_commonPrefix, "");
- }
- const urlbar = document.getElementById("urlbar");
- urlbar.value = new_value;
- urlbar.setSelectionRange(acm_typedPrefix.length, urlbar.textLength);
- }
- }
-
- // for debugging output
- function acm_console(msg) {
- const consoleService = Components.classes["@mozilla.org/consoleservice;1"]
- .getService(Components.interfaces.nsIConsoleService);
- consoleService.logStringMessage(msg);
- }
-
- // invalidates the caches of all the main browser windows; needed because
- // every window maintains its own instances of the acm_* global variables
- function acm_invalidateCaches()
- {
- var browser_windows = acm_mediator.getEnumerator("navigator:browser");
- while (browser_windows.hasMoreElements())
- browser_windows.getNext().acm_lastPrefix = null;
- }
-
- // handles text being typed in the location bar
- function acm_urlbarOnInput(event)
- {
- // do not display popup if Autocomplete is off
- if (acm_getPreference(ACM_ACTIVE_COMPONENT) === "off")
- return;
-
- // popup has been temporarily disabled
- if (acm_disablePopup)
- return;
-
- // prevent re-display of popup when deleting an entry or for a clickngo middle click on a new tab
- if (acm_preventPopup) {
- acm_preventPopup = false;
- return;
- }
-
- // enable inlining if characters have been added to the prefix
- const urlbar = document.getElementById("urlbar");
- if (acm_typedPrefix !== null && urlbar.value.length > acm_typedPrefix.length && acm_disableInlining)
- acm_disableInlining = false;
-
- var lastPrefix = acm_typedPrefix;
- acm_typedPrefix = urlbar.value;
-
- if (acm_getPreference(ACM_SHOW_ONARROW) && !acm_popupExists)
- return;
-
- // the urlbar is filled with the most recently loaded URL (possible blank) when Esc is pressed on
- // the popup in a full-screen Open Web Location dialog;
- // restore acm_typedPrefix to its previous value, and do not set acm_popupExists to false,
- // since that will be done in the Esc handler
- if (!document.getElementById("urlbar-container")) {
- var lastURL = acm_prefs.getComplexValue("general.open_location.last_url",
- Components.interfaces.nsISupportsString).data;
- if (lastPrefix !== null && acm_typedPrefix === lastURL) {
- acm_typedPrefix = lastPrefix;
- return;
- }
- }
-
- // hide popup if location bar was cleared
- if (acm_typedPrefix === null || acm_typedPrefix === "") {
- // || acm_typedPrefix === window._content.document.location.href) {
-
- acm_typingTimer.cancel();
- if (acm_popupExists) {
- acm_popupExists = false;
- const popup = document.getElementById("ACM_Popup");
- popup.hidePopup();
- }
- return;
- }
-
- // restart typing timer
- acm_typingTimer.cancel();
- acm_typingTimer.init(acm_timerObserver, acm_timerDelay, acm_typingTimer.TYPE_ONE_SHOT);
- }
-
- // handles keyboard navigation on the location bar and the popup
- function acm_urlbarNavigation(event)
- {
-
- const urlbar = document.getElementById("urlbar");
- const popup = document.getElementById("ACM_Popup");
- var changePos;
-
- if (event.altKey) {
- var key = event.charCode;
-
- // Alt+L places the focus on the location bar, temporarily disabling the popup
- // HACK: for the Open Web Location dialog, the wrong char code is given to us!?
- if ( (document.getElementById("urlbar-container") && key === event.DOM_VK_L)
- || (document.getElementById("openLocation") &&key === event.DOM_VK_SEPARATOR) ) {
- acm_typingTimer.cancel();
- if (acm_popupExists) {
- acm_popupExists = false;
- popup.hidePopup();
- }
- urlbar.select();
- acm_disablePopup = true;
- event.preventDefault();
- event.stopPropagation();
- return;
- }
- }
-
- // only for the main location bar
- if (event.ctrlKey && document.getElementById("urlbar-container")) {
- var key = event.charCode;
-
- // Ctrl+<number> re-sorts the suggestion list according to the corresponding criterion
- if (acm_popupExists && key >= event.DOM_VK_0 && key <= event.DOM_VK_9) {
- // remove bookmarks separator, as it is going to be re-inserted by acm_buildPopup()
- if (acm_matching_bookmarks > 0 && acm_matching_bookmarks !== acm_suggestions.length)
- acm_lastResults.splice(acm_matching_bookmarks, 1);
-
- switch (key) {
- case event.DOM_VK_1:
- acm_showTooltip(0);
- acm_buildPopup(acm_lastResults.sort(acm_defaultCompareFun));
- break;
- case event.DOM_VK_2:
- acm_showTooltip(1);
- acm_buildPopup(acm_lastResults.sort(acm_topCompareFun));
- break;
- case event.DOM_VK_3:
- acm_showTooltip(2);
- acm_buildPopup(acm_lastResults.sort(acm_mfuCompareFun));
- break;
- case event.DOM_VK_4:
- acm_showTooltip(3);
- acm_buildPopup(acm_lastResults.sort(acm_mruCompareFun));
- break;
- case event.DOM_VK_5:
- acm_showTooltip(4);
- acm_buildPopup(acm_lastResults.sort(acm_alphaURLCompareFun));
- break;
- case event.DOM_VK_6:
- acm_showTooltip(5);
- acm_buildPopup(acm_lastResults.sort(acm_alphaTitleCompareFun));
- break;
- default:
- // restore the bookmarks separator, which we removed before re-sorting
- if (acm_matching_bookmarks > 0 && acm_matching_bookmarks !== acm_suggestions.length)
- acm_lastResults.splice(acm_matching_bookmarks, 0, new AutocompleteCandidate());
- break;
- }
-
- // prevent other elements from handling this event (necessary for Windows only!)
- event.preventDefault();
- event.stopPropagation();
-
- return;
- }
- }
-
- if ( (event.keyCode === event.DOM_VK_TAB) && acm_popupExists ) {
- changePos = (event.shiftKey) ? -1 : 1;
-
- // Tab completion; doesn't work yet!
- /* if (!event.shiftKey) {
- // we are on the location bar; fill in the longest common prefix of all suggestions' URLs
- if (acm_popupTreePos === -1) {
- var lcp = acm_longestCommonPrefix(acm_suggestions);
-
- }
- else { // we are on the popup; filter suggestions based on current location bar value
-
- //for (var i = acm_suggestions.length - 1; i >= 0; i--) {
- // if (acm_suggestions[i])
- // acm_suggestions.splice(i, 1);
- //}
- }
- }
- // undo last action
- else {
-
- } */
-
- // prevent other elements from handling this event
- event.preventDefault();
- event.stopPropagation();
- }
-
- // Del or Shift+Del deletes an entry
- else if (event.keyCode === event.DOM_VK_DELETE && acm_popupExists
- && acm_popupTreePos > -1) {
- // ignore if it's a bookmarks separator
- if (acm_popupTreePos === acm_matching_bookmarks && acm_matching_bookmarks > 0
- && acm_matching_bookmarks !== acm_suggestions.length) {
- event.preventDefault();
- event.stopPropagation();
- return;
- }
-
- // if it is a history entry, delete it from the history file
- if (acm_suggestions[acm_popupTreePos].source === ACM_SOURCE_HISTORY) {
- var uriToDelete = acm_ioService.newURI(acm_suggestions[acm_popupTreePos].URL, null, null);
- acm_browserHistory.removePage(uriToDelete);
- }
- // if it is a bookmark, just remove it from the candidates array
- else if (acm_suggestions[acm_popupTreePos].source === ACM_SOURCE_BOOKMARKS)
- acm_Aggregator.singleton().removeSingleBookmark(acm_suggestions[acm_popupTreePos].resource,
- acm_suggestions[acm_popupTreePos].URL);
-
- // find what the new active suggestion should be after the reconstruction of the popup
- var newSelection = (acm_popupTreePos < acm_suggestions.length - 1) ?
- acm_popupTreePos : acm_suggestions.length - 2;
-
- if (newSelection === -1) { // no suggestions left, close popup
- acm_popupExists = false;
- popup.hidePopup();
- return;
- }
-
- // was a bookmark removed?
- var bookmarkRemoved = false;
- if (acm_matching_bookmarks > 0
- && acm_suggestions[acm_popupTreePos].source === ACM_SOURCE_BOOKMARKS)
- bookmarkRemoved = true;
-
- // remove bookmarks separator, as it is going to be re-inserted by acm_buildPopup()
- if (acm_matching_bookmarks > 0 && acm_matching_bookmarks !== acm_suggestions.length)
- acm_suggestions.splice(acm_matching_bookmarks, 1);
-
- // decrement acm_matching_bookmarks if needed
- if (bookmarkRemoved && acm_matching_bookmarks > 0)
- acm_matching_bookmarks--;
-
- // remove selected entry (remember, we might have removed the bookmarks separator already)
- acm_popupTreePos = (bookmarkRemoved || acm_matching_bookmarks < 1) ?
- acm_popupTreePos : acm_popupTreePos - 1;
- acm_suggestions.splice(acm_popupTreePos, 1);
-
- // update cached results and redraw the popup, even if we haven't removed an entry
- // NOTE: acm_buildPopup() resets acm_popupTreePos, so we have to restore it for acm_showPopup()
- acm_lastResults = acm_suggestions;
- acm_buildPopup(acm_lastResults);
- acm_popupTreePos = newSelection;
-
- // changing urlbar.value triggers 'oninput' on Windows (and in Firefox 1.0)
- // NOTE: always do this after invoking acm_buildPopup()
- acm_preventPopup = true;
-
- if (acm_popupTreePos === acm_matching_bookmarks && acm_matching_bookmarks > 0
- && acm_matching_bookmarks !== acm_suggestions.length)
- urlbar.value = acm_typedPrefix;
- else
- urlbar.value = acm_suggestions[acm_popupTreePos].URL;
-
- return;
- }
-
- // Alt+Down, Alt+Up, or F4 toggle the history popup; Ctrl+Up/Down switches tabs
- else if (event.keyCode === event.DOM_VK_DOWN) {
- if (event.altKey || event.ctrlKey)
- return;
-
- // re-enable popup if it has been temporarily disabled
- acm_disablePopup = false;
-
- changePos = 1;
- }
-
- else if (event.keyCode === event.DOM_VK_UP) {
- if (event.altKey || event.ctrlKey)
- return;
-
- changePos = -1;
- }
-
- // full screen mode; fix for bug 228355
- else if (event.keyCode === event.DOM_VK_F11) {
- if (acm_popupExists) {
- acm_popupExists = false;
- popup.hidePopup();
- }
- return;
- }
-
- // close popup for Ctrl+PgUp/PgDown (switching tabs)
- else if (event.keyCode === event.DOM_VK_PAGE_DOWN) {
- if (event.ctrlKey) {
- if (acm_popupExists) {
- acm_popupExists = false;
- popup.hidePopup();
- }
- return;
- }
- else {
- if (acm_popupTreePos !== -1)
- changePos = acm_maxrows - 1;
- // move to first suggestion from location bar
- else
- changePos = 1;
- }
- }
-
- else if (event.keyCode === event.DOM_VK_PAGE_UP) {
- if (event.ctrlKey) {
- if (acm_popupExists) {
- acm_popupExists = false;
- popup.hidePopup();
- }
- return;
- }
- else {
- if (acm_popupTreePos !== -1)
- changePos = -(acm_maxrows - 1);
- // move to last suggestion from location bar
- else
- changePos = acm_suggestions.length;
- }
- }
-
- // delete possibly inlined URL, but do not close the popup
- // NOTE: the use of Ctrl apparently changes the char codes!?
- else if (event.keyCode === event.DOM_VK_DELETE || event.keyCode === event.DOM_VK_BACK_SPACE
- || (event.ctrlKey && event.charCode - 32 === event.DOM_VK_X) ) {
- if (acm_popupExists) {
- // cursor is on the location bar
- if (acm_popupTreePos === -1) {
- if (acm_getPreference(ACM_INLINE) && acm_suggestions[0].matched_against.indexOf("b-") === 0
- && !acm_disableInlining) {
- // fix for bug 135019
- urlbar.value = urlbar.value.substring(0, urlbar.selectionStart);
- acm_disableInlining = true;
- }
- else
- urlbar.value = acm_typedPrefix;
- }
- // cursor is somewhere on the popup; no part of the URL is selected
- else {
- urlbar.value = acm_suggestions[acm_popupTreePos].URL;
- if (acm_getPreference(ACM_INLINE) && !acm_disableInlining) {
- acm_disableInlining = true;
- acm_typedPrefix = urlbar.value;
- }
- }
- }
- // deleting a part of the URL when there is no popup shouldn't trigger inline autocomplete
- else {
- if (acm_getPreference(ACM_INLINE) && !acm_disableInlining) {
- acm_disableInlining = true;
- acm_typedPrefix = urlbar.value;
- }
- }
-
- return;
- }
-
- // close the popup, inlining the selected address, but do not load the page
- else if (event.keyCode === event.DOM_VK_LEFT
- || event.keyCode === event.DOM_VK_RIGHT
- || event.keyCode === event.DOM_VK_HOME
- || event.keyCode === event.DOM_VK_END) {
- // cancel the timer, so that the popup does not appear
- acm_typingTimer.cancel();
-
- if (acm_popupExists) {
- // cursor is on the location bar
- if (acm_popupTreePos === -1) {
- if (acm_getPreference(ACM_INLINE) && acm_suggestions[0].matched_against.indexOf("b-") === 0
- && !acm_disableInlining)
- urlbar.value = acm_suggestions[0][acm_suggestions[0].matched_against.substr(2)];
- else
- urlbar.value = acm_typedPrefix;
- }
- // cursor is somewhere on the popup
- else
- urlbar.value = acm_suggestions[acm_popupTreePos].URL;
-
- acm_popupExists = false;
- popup.hidePopup();
- }
- return;
- }
-
- else if (event.keyCode === event.DOM_VK_ESCAPE) {
- // cancel the timer, so that the popup does not appear after Esc is pressed
- acm_typingTimer.cancel();
-
- if (acm_popupExists) {
- urlbar.value = acm_typedPrefix;
- acm_popupExists = false;
- popup.hidePopup();
-
- // prevent other elements from handling this event
- event.preventDefault();
- event.stopPropagation();
- }
- else {
- urlbar.setAttribute("popupOpen", "false");
-
- if (document.getElementById("urlbar-container"))
- handleURLBarRevert();
- }
-
- // re-enable popup if it has been temporarily disabled
- acm_disablePopup = false;
-
- return;
- }
-
- // runs after the ontextentered handler
- else if (event.keyCode === event.DOM_VK_ENTER || event.keyCode === event.DOM_VK_RETURN) {
- // Enter on the bookmarks separator
- // NOTE: if the popup is off, acm_matching_bookmarks retains its value from last time
- if (acm_popupExists
- && acm_treePopup.view.selection.currentIndex === acm_matching_bookmarks
- && acm_matching_bookmarks > 0 && acm_matching_bookmarks !== acm_suggestions.length)
- return;
-
- // fix for bug 101497, if text in location bar is not fully selected, e.g., after a Ctrl+L
- // NOTE: don't move this down!
- if (acm_getPreference(ACM_INLINE) && urlbar.selectionStart !== urlbar.selectionEnd
- && urlbar.selectionStart !== 0)
- urlbar.value = acm_suggestions[0].URL;
-
- // cancel the timer, so that the popup does not appear after Enter is pressed
- acm_typingTimer.cancel();
-
- // hide the popup
- var popupExisted = false;
- if (acm_popupExists) {
- popupExisted = true;
- acm_popupExists = false;
- popup.hidePopup();
- }
-
- // re-enable popup if it has been temporarily disabled
- acm_disablePopup = false;
-
- // non-browser location bar: if the popup was open, inline the URL but do not close the
- // dialog, otherwise load the existing URL
- if (!document.getElementById("urlbar-container")) {
- if (popupExisted) {
- event.preventDefault();
- event.stopPropagation();
- }
- return;
- }
-
- // load the URL
- // NOTE: other extensions (e.g., Tabbrowser Preferences, DeviantLink) may define
- // their own custom 'ontextentered' handler, which may itself have a 'param' argument;
- // replace all such arguments with 'acm_loadParams' and then invoke the handler
- var originalHandler = acm_ontextenteredHandler.replace("param", "acm_loadParams", "g");
- // NOTE: no 'return' is allowed in eval()
- originalHandler = originalHandler.replace("return ", "");
- eval(originalHandler);
- return;
- }
-
- // return for most other keystrokes
- else {
- // hide popup on arbitrary keyboard shortcut
- if (event.shiftKey || event.ctrlKey || event.altKey
- || (event.keyCode >= event.DOM_VK_F1 && event.keyCode <= event.DOM_VK_F24
- && event.keyCode !== event.DOM_VK_F4) // F4 needs acm_popupExists to be true
- && acm_popupExists) {
- // do not close popup for common Shift combinations for special characters
- // than can appear on the location bar
- var key = event.charCode;
- if ( (key >= 33 && key <= 38) || (key >= 40 && key <= 43) || key === 58 || key === 60
- || (key >= 62 && key <= 64) || key === 94 || key === 95 || (key >= 123 && key <= 126) )
- return;
-
- // for extra French keyboard special characters
- if (key === 46 || key === 47 || (key >= 51 && key <= 56) || key === 163 || key === 176)
- return;
-
- // NOTE: The use of Shift apparently changes the char codes!?
- key -= 32;
-
- // fix for bug 91536; see https://bugzilla.mozilla.org/show_bug.cgi?id=91536#c4
- if ( (key === event.DOM_VK_X && urlbar.selectionStart === 0
- && urlbar.selectionEnd === urlbar.textLength)
- || (key !== event.DOM_VK_A && key !== event.DOM_VK_C && key !== event.DOM_VK_L
- && key !== event.DOM_VK_X && key !== event.DOM_VK_Z) ) {
- acm_popupExists = false;
- popup.hidePopup();
- }
- }
- return;
- }
-
- // return if Autocomplete is off
- if (acm_getPreference(ACM_ACTIVE_COMPONENT) === "off")
- return;
-
- // if there is no popup yet, build and display it;
- // this executes only for arrow up/down and Page Up/Down
- if (!acm_popupExists) {
- acm_typedPrefix = acm_lastPrefix = urlbar.value;
-
- // for the blank search string, Firefox uses the order by which entries were entered
- // in the history file; we use most recently visited.
- if (acm_typedPrefix === "") {
- // set the number of matching bookmarks for placing the bookmarks separator on the popup
- if (acm_getPreference(ACM_MATCH_BOOKMARKS) && acm_getPreference(ACM_BOOKMARKS_FIRST))
- acm_matching_bookmarks = acm_Aggregator.singleton().bookmarks.length;
- else
- acm_matching_bookmarks = -1;
-
- acm_buildPopup(acm_Aggregator.singleton().allCandidates.sort(acm_mruCompareFun));
- }
- else {
- acm_lastResults = acm_getSortedSuggestionList(null);
- acm_buildPopup(acm_lastResults);
- }
- return;
- }
-
- // deselect text in the location bar since we are on the popup
- if (acm_getPreference(ACM_INLINE))
- urlbar.setSelectionRange(urlbar.textLength, urlbar.textLength);
-
- // update tree selection; -1 indicates we are on the location bar
- // NOTE: PgUp/PgDown from location bar is handled in the respective keyboard handlers
- // HOWTOFIX: when we Page Down on the popup, the right end of a long URL is displayed
- var newTreePos = acm_popupTreePos + changePos;
- if (newTreePos < 0) {
- // page up on the first page; move to first suggestion
- if (acm_popupTreePos >= 1 && acm_popupTreePos <= acm_maxrows - 1)
- newTreePos = 0;
- // page up from first suggestion; move to location bar
- else if (acm_popupTreePos === 0)
- newTreePos = -1;
- // arrow up from location bar
- else
- newTreePos = acm_suggestions.length - 1;
- }
-
- else if (newTreePos > acm_suggestions.length - 1) {
- // page down on the last page; move to last suggestion
- if (acm_popupTreePos >= acm_suggestions.length - acm_maxrows - 1
- && acm_popupTreePos <= acm_suggestions.length - 2)
- newTreePos = acm_suggestions.length - 1;
- // page down from last suggestion; move to location bar
- else
- newTreePos = -1;
- }
-
- // otherwise, do nothing
- //else
- // ;
-
- // move to new position on tree
- if (newTreePos === -1) {
- acm_treePopup.view.selection.clearSelection();
- acm_treePopup.treeBoxObject.scrollToRow(0);
- }
- else {
- acm_treePopup.view.selection.select(newTreePos);
- acm_treePopup.treeBoxObject.ensureRowIsVisible(newTreePos);
- }
- acm_popupTreePos = newTreePos;
-
- // update location bar value
- if ( (newTreePos === -1)
- || (newTreePos === acm_matching_bookmarks && acm_matching_bookmarks > 0
- && acm_matching_bookmarks !== acm_suggestions.length) )
- urlbar.value = acm_typedPrefix;
- else
- urlbar.value = acm_suggestions[newTreePos].URL;
- }
-
- // re-builds and displays the popup, populated with entries from the argument sorted suggestion list
- function acm_buildPopup(sortedList)
- {
- const urlbar = document.getElementById("urlbar");
- const popup = document.getElementById("ACM_Popup");
-
- // if no entries matched, hide popup and return
- // NOTE: this is also the case when Autocomplete is turned off at browser startup
- if (sortedList.length === 0) {
- if (acm_popupExists) {
- acm_popupExists = false;
- popup.hidePopup();
- }
- return;
- }
-
- // construct the tree for the popup
- acm_suggestions = sortedList;
-
- // add a stub entry for the bookmarks separator if at least one bookmark matched
- if (acm_getPreference(ACM_MATCH_BOOKMARKS) && acm_getPreference(ACM_BOOKMARKS_FIRST)
- && acm_matching_bookmarks > 0 && acm_matching_bookmarks !== acm_suggestions.length)
- acm_suggestions.splice(acm_matching_bookmarks, 0, new AutocompleteCandidate());
-
- if (!acm_treePopup)
- acm_treePopup = document.getAnonymousElementByAttribute(popup, "anonid", "tree");
- else {
- // used when deleting a suggestion to re-center the popup
- var firstVisibleRow = acm_treePopup.treeBoxObject.getFirstVisibleRow();
- acm_treePopup.treeBoxObject.invalidate();
- }
-
- acm_treePopupView.rowCount = acm_suggestions.length;
- acm_treePopup.treeBoxObject.view = acm_treePopupView;
-
- // NOTE: this doesn't work, so set the 'height' property instead
- //acm_treePopup.setAttribute("rows", visible_rows);
-
- // calculate the number of visible rows before restoring acm_maxrows
- var visible_rows = (acm_suggestions.length > acm_maxrows) ? acm_maxrows : acm_suggestions.length;
-
- // show and hide the popup once to get the row height
- if (!acm_rowHeight) {
- popup.showPopup(urlbar, -1, -1, "popup", "bottomleft", "topleft");
- acm_rowHeight = acm_treePopup.treeBoxObject.rowHeight;
- popup.hidePopup(); // restores acm_maxrows and adds 'keypress' event listener
- }
-
- // temporarily disable keyboard tab selection, since it conflicts with on-the-fly re-sorting
- // on Windows; will re-enable it when the popup is hidden
- // NOTE: this is defined in browser.js, not other places we support (e.g., Open Web Location dialog)
- if (document.getElementById("urlbar-container"))
- window.removeEventListener("keypress", ctrlNumberTabSelection, false);
-
- // set popup height and scrollbar
-
- acm_treePopup.setAttribute("height", visible_rows * acm_rowHeight);
- acm_treePopup.setAttribute("hidescrollbar", acm_suggestions.length <= acm_maxrows);
- acm_popupTreePos = -1; // we are on the location bar
-
- // determine column order
- // NOTE: do not use columns[], since the tree does not exist yet
- var show_titles = acm_getPreference(ACM_SHOW_TITLES);
- var swap_columns = acm_getPreference(ACM_SWAP_COLUMNS);
- var colURL, colTitle;
-
- if (show_titles && swap_columns) {
- // we are in the initial state; swap columns
- if (acm_treePopup.firstChild.childNodes[0].getAttribute("id") === "colURL") {
- colURL = acm_treePopup.firstChild.childNodes[0];
- colTitle = acm_treePopup.firstChild.childNodes[1];
- acm_treePopup.firstChild.insertBefore(colTitle, colURL);
- }
- // columns have been swapped already; leave it that way
- else {
- colURL = acm_treePopup.firstChild.childNodes[1];
- colTitle = acm_treePopup.firstChild.childNodes[0];
- }
- }
- else {
- // we are in the initial state; leave it that way
- if (acm_treePopup.firstChild.childNodes[0].getAttribute("id") === "colURL") {
- colURL = acm_treePopup.firstChild.childNodes[0];
- colTitle = acm_treePopup.firstChild.childNodes[1];
- }
- // restore initial state
- else {
- colURL = acm_treePopup.firstChild.childNodes[1];
- colTitle = acm_treePopup.firstChild.childNodes[0];
- acm_treePopup.firstChild.insertBefore(colURL, colTitle);
- }
- }
-
- // determine the visible columns and their crop modes
- colURL.setAttribute("crop", acm_getPreference(ACM_ADDRESS_TRUNC));
-
- if (show_titles) {
- colTitle.setAttribute("crop", acm_getPreference(ACM_TITLE_TRUNC));
- colTitle.setAttribute("hidden", "false");
- }
- else
- colTitle.setAttribute("hidden", "true");
-
- var colSource = acm_treePopup.firstChild.childNodes[2];
- if (acm_getPreference(ACM_SHOW_DATE))
- colSource.setAttribute("hidden", "false");
- else
- colSource.setAttribute("hidden", "true");
-
- // set column widths heuristically
- // NOTE: if these are set in acpopup.xml, they don't adapt dynamically to a column swap
- colURL.setAttribute("flex", 12);
- colTitle.setAttribute("flex", 6);
- colSource.setAttribute("flex", 5);
-
- // show popup; workaround for bug 348146 that only appears on Mac OS X
- // NOTE: set this to 'true' to make inline autocompletion work the first time the popup
- // appears, and also so that the popup is not shown after buttons have been pressed
- acm_popupExists = true;
- setTimeout(acm_showPopup, 0, firstVisibleRow);
- }
-
- // shows the popup; firstVisibleRow is used when deleting a suggestion to re-center the popup
- function acm_showPopup(firstVisibleRow)
- {
- // needed due to the async nature (setTimeout() call) of the popup creation
- if (!acm_popupExists)
- return;
-
- const urlbar = document.getElementById("urlbar");
- const popup = document.getElementById("ACM_Popup");
- popup.showPopup(urlbar, -1, -1, "popup", "bottomleft", "topleft");
-
- if (acm_popupTreePos === -1) { // new popup
- acm_treePopup.view.selection.select(-1);
- acm_treePopup.treeBoxObject.scrollToRow(0);
- }
- else { // after deleting an entry
- acm_treePopup.view.selection.select(acm_popupTreePos);
-
- // NOTE: acm_treePopup.treeBoxObject.getLastVisibleRow() returns acm_suggestions.length + 1
- // on the last popup page (if that page is not also the first)!?
- if (acm_popupTreePos >= acm_suggestions.length - acm_maxrows + 1
- && acm_popupTreePos <= acm_suggestions.length - 1
- && firstVisibleRow !== 0)
- acm_treePopup.treeBoxObject.scrollToRow(firstVisibleRow - 1);
- else
- acm_treePopup.treeBoxObject.scrollToRow(firstVisibleRow);
- }
- }
-
- // shows the urlbar tooltip
- function acm_showTooltip(tooltipIndex)
- {
- // another tooltip is being displayed
- if (acm_tooltipTimeout !== null) {
- acm_tooltip.setAttribute("hidden", true);
- clearTimeout(acm_tooltipTimeout);
- }
-
- // the tooltip labels are stored in a deck
- acm_tooltip = document.getElementById("acm_resorting-deck").childNodes.item(tooltipIndex);
- acm_tooltip.setAttribute("hidden", false);
- acm_tooltipTimeout = setTimeout(acm_hideTooltip, 3000);
- }
-
- // hides the urlbar tooltip (after a timeout set in acm_showTooltip())
- function acm_hideTooltip()
- {
- acm_tooltip.setAttribute("hidden", true);
- acm_tooltipTimeout = null;
- }
-
- // toggles history dropdown; triggered by Alt+Up, Alt+Down, or F4 on the location bar.
- // Firefox uses the order by which entries were entered in the history file,
- // we use most recently visited.
- function acm_toggleHistoryPopup()
- {
- // return if Autocomplete is off
- if (acm_getPreference(ACM_ACTIVE_COMPONENT) === "off")
- return;
-
- if (!acm_popupExists) {
- if (acm_typingTimer)
- acm_typingTimer.cancel();
-
- // is restored to its regular value on 'popuphidden'
- acm_maxrows = document.getElementById("urlbar").maxDropMarkerRows;
-
- // set the number of matching bookmarks for placing the bookmarks separator on the popup
- if (acm_getPreference(ACM_MATCH_BOOKMARKS) && acm_getPreference(ACM_BOOKMARKS_FIRST))
- acm_matching_bookmarks = acm_Aggregator.singleton().bookmarks.length;
- else
- acm_matching_bookmarks = -1;
-
- acm_buildPopup(acm_Aggregator.singleton().allCandidates.sort(acm_mruCompareFun));
- acm_lastPrefix = ""; // invalidate window cache
- }
- else {
- acm_popupExists = false;
- const popup = document.getElementById("ACM_Popup");
- popup.hidePopup();
- }
- }
-
- // handles mouse clicks on popup items
- // NOTE: mouse selection/navigation happens separately from keyboard selection/navigation
- function acm_popupMouseClick(event, popup)
- {
- // mouse click on the bookmarks separator
- if (acm_treePopup.view.selection.currentIndex === acm_matching_bookmarks
- && acm_matching_bookmarks > 0 && acm_matching_bookmarks !== acm_suggestions.length)
- return;
-
- // on the browser location bar
- if (document.getElementById("urlbar-container")) {
- // left or right mouse button
- if (event.button === 0 || event.button === 2)
- acm_popupItemSelect(event, popup, true);
-
- // middle mouse button opens a new tab; fix for bug 295498
- else if (event.button === 1) {
- var new_url = acm_suggestions[acm_treePopup.view.selection.currentIndex].URL;
- acm_popupExists = false;
- popup.hidePopup();
- // open tab in foreground or background, based on user preference
- var back = acm_getPreference(ACM_LOAD_TAB_IN_BACKGROUND);
- var newtab = getBrowser().addTab(new_url);
- if (!back)
- getBrowser().selectedTab = newtab;
- }
- }
- // on a dialog's location bar
- else
- acm_popupItemSelect(event, popup, false);
- }
-
- // handles selection of a popup item
- function acm_popupItemSelect(event, popup, loadURL)
- {
- var new_url = acm_suggestions[acm_treePopup.view.selection.currentIndex].URL;
- if (loadURL)
- window._content.document.location.href = new_url;
- else
- document.getElementById("urlbar").value = new_url;
- acm_popupExists = false;
- popup.hidePopup();
- }
-
- // handles mouse-over events for popup items
- function acm_popupMouseMove(event)
- {
- // update the tree selection
- acm_popupTreePos = acm_treePopup.view.selection.currentIndex;
- }
-
- // prevents the popup from appearing after a clickngo middle mouse click on a new tab
- function acm_urlbarMouseUp(event)
- {
- // only for the browser location bar
- if (document.getElementById("urlbar-container") && event.button === 1)
- acm_preventPopup = true;
- }
-
- // opens a URL from a non-browser's location bar; code taken from
- // chrome://content/browser/openLocation.js::open()
- function acm_loadURL()
- {
- if ("arguments" in window && window.arguments.length >= 1)
- browser = window.arguments[0];
-
- var url;
- var postData = {};
- if (browser)
- url = browser.getShortcutOrURI(document.getElementById("urlbar").value, postData);
- else
- url = document.getElementById("urlbar").value;
-
- try {
- // Whichever target we use for the load, we allow third-party services to
- // fixup the URI
- switch (document.getElementById("openWhereList").value) {
- case "0":
- browser.loadURI(url, null, postData.value, true);
- break;
- case "1":
- window.opener.delayedOpenWindow(getBrowserURL(), "all,dialog=no",
- url, postData.value, null, null, true);
- break;
- case "3":
- if (browser.getBrowser && browser.getBrowser().localName == "tabbrowser")
- browser.delayedOpenTab(url, null, null, postData.value, true);
- else
- browser.loadURI(url, null, postData.value, true); // Just do a normal load.
- break;
- }
- }
- catch(exception) {
- }
-
- if (acm_prefs) {
- var str = Components.classes["@mozilla.org/supports-string;1"]
- .createInstance(Components.interfaces.nsISupportsString);
- str.data = document.getElementById("urlbar").value;
- acm_prefs.setComplexValue("general.open_location.last_url",
- Components.interfaces.nsISupportsString, str);
- acm_prefs.setIntPref("general.open_location.last_window_choice",
- document.getElementById("openWhereList").value);
- }
-
- // Delay closing slightly to avoid timing bug on Linux.
- window.close();
- return false;
- }
-
- // matches the user-typed prefix against the provided list of AutocompleteCandidate's and sorts the results
- function acm_getSortedSuggestionList(list)
- {
- acm_bookfirst = acm_getPreference(ACM_BOOKMARKS_FIRST);
-
- if (acm_getPreference(ACM_SORTBY) === "default")
- return acm_getFilteredCandidates(list).sort(acm_defaultCompareFun);
- else if (acm_getPreference(ACM_SORTBY) === "top")
- return acm_getFilteredCandidates(list).sort(acm_topCompareFun);
- else if (acm_getPreference(ACM_SORTBY) === "mfu")
- return acm_getFilteredCandidates(list).sort(acm_mfuCompareFun);
- else if (acm_getPreference(ACM_SORTBY) === "mru")
- return acm_getFilteredCandidates(list).sort(acm_mruCompareFun);
- else if (acm_getPreference(ACM_SORTBY) === "alpha_address") {
- acm_checkBookFirst = true;
- var matches = acm_getFilteredCandidates(list).sort(acm_alphaURLCompareFun);
- acm_checkBookFirst = false;
- return matches;
- }
- else if (acm_getPreference(ACM_SORTBY) === "alpha_title")
- return acm_getFilteredCandidates(list).sort(acm_alphaTitleCompareFun);
- else // fallback on error
- return acm_getFilteredCandidates(list).sort(acm_defaultCompareFun);
- }
-
- // Firefox default ordering
- // - if the URL ends with a slash (Web path) or if it has been manually typed,
- // add 5 to its visit count
- // - sort in order of decreasing visit count
- // - on a visit count tie, place Web paths first
- // - if both addresses represent Web paths, sort in ascending alphabetical order,
- // after ignoring common protocols and prefixes
- // The order calculated by this function is not exactly the order Firefox would
- // end up with, since an extension currently has no way of finding out whether
- // an address has been manually typed.
- function acm_defaultCompareFun(candidateA, candidateB)
- {
- if (acm_bookfirst) {
- if (candidateA.source === ACM_SOURCE_BOOKMARKS && candidateB.source !== ACM_SOURCE_BOOKMARKS)
- return -1;
- else if (candidateA.source !== ACM_SOURCE_BOOKMARKS && candidateB.source === ACM_SOURCE_BOOKMARKS)
- return 1;
- }
-
- var AisWebpath = candidateA.webpath;
- var BisWebpath = candidateB.webpath;
-
- var countA = candidateA.visit_count;
- if (AisWebpath)
- countA += 5;
-
- var countB = candidateB.visit_count;
- if (BisWebpath)
- countB += 5;
-
- if (countA > countB) // place A before B
- return -1;
- else if (countA < countB)
- return 1;
- else {
- if (AisWebpath && !BisWebpath)
- return -1;
- else if (!AisWebpath && BisWebpath)
- return 1;
- else
- return acm_alphaURLCompareFun(candidateA, candidateB);
- }
- }
-
- // place domain addresses first sorting them in ascending alphabetical order;
- // sort the rest also in ascending alphabetical order
- function acm_topCompareFun(candidateA, candidateB)
- {
- if (acm_bookfirst) {
- if (candidateA.source === ACM_SOURCE_BOOKMARKS && candidateB.source !== ACM_SOURCE_BOOKMARKS)
- return -1;
- else if (candidateA.source !== ACM_SOURCE_BOOKMARKS && candidateB.source === ACM_SOURCE_BOOKMARKS)
- return 1;
- }
-
- var AisDomain = candidateA.domain;
- var BisDomain = candidateB.domain;
-
- if (AisDomain && !BisDomain) // place A before B
- return -1;
- else if (!AisDomain && BisDomain)
- return 1;
- else
- return acm_alphaURLCompareFun(candidateA, candidateB);
- }
-
- // sort in order of decreasing visit count,
- // or in the case of a tie, in ascending alphabetical order
- function acm_mfuCompareFun(candidateA, candidateB)
- {
- if (acm_bookfirst) {
- if (candidateA.source === ACM_SOURCE_BOOKMARKS && candidateB.source !== ACM_SOURCE_BOOKMARKS)
- return -1;
- else if (candidateA.source !== ACM_SOURCE_BOOKMARKS && candidateB.source === ACM_SOURCE_BOOKMARKS)
- return 1;
- }
-
- var countA = candidateA.visit_count;
- var countB = candidateB.visit_count;
-
- if (countA > countB) // place A before B
- return -1;
- else if (countA < countB)
- return 1;
- else
- return acm_alphaURLCompareFun(candidateA, candidateB);
- }
-
- // sort in order of decreasing last visit date,
- // or in the case of a tie, in ascending alphabetical order
- function acm_mruCompareFun(candidateA, candidateB)
- {
- if (acm_bookfirst) {
- if (candidateA.source === ACM_SOURCE_BOOKMARKS && candidateB.source !== ACM_SOURCE_BOOKMARKS)
- return -1;
- else if (candidateA.source !== ACM_SOURCE_BOOKMARKS && candidateB.source === ACM_SOURCE_BOOKMARKS)
- return 1;
- }
-
- var visitA = candidateA.last_visit;
- var visitB = candidateB.last_visit;
-
- if (visitA > visitB) // place A before B
- return -1;
- else if (visitA < visitB)
- return 1;
- else
- return acm_alphaURLCompareFun(candidateA, candidateB);
- }
-
- // sort in ascending alphabetical order by title
- function acm_alphaTitleCompareFun(candidateA, candidateB)
- {
- if (acm_bookfirst) {
- if (candidateA.source === ACM_SOURCE_BOOKMARKS && candidateB.source !== ACM_SOURCE_BOOKMARKS)
- return -1;
- else if (candidateA.source !== ACM_SOURCE_BOOKMARKS && candidateB.source === ACM_SOURCE_BOOKMARKS)
- return 1;
- }
-
- // manufacture appropriate objects to pass as arguments
- var candA = new Object();
- candA.strippedURL = candidateA.strippedTitle;
- candA.URL = "";
- var candB = new Object();
- candB.strippedURL = candidateB.strippedTitle;
- candB.URL = "";
-
- return acm_alphaURLCompareFun(candA, candB);
- }
-
- // sort in ascending alphabetical order by address, after ignoring common protocols and prefixes
- function acm_alphaURLCompareFun(candidateA, candidateB)
- {
- if (acm_checkBookFirst && acm_bookfirst) {
- if (candidateA.source === ACM_SOURCE_BOOKMARKS && candidateB.source !== ACM_SOURCE_BOOKMARKS)
- return -1;
- else if (candidateA.source !== ACM_SOURCE_BOOKMARKS && candidateB.source === ACM_SOURCE_BOOKMARKS)
- return 1;
- }
-
- var urlA = candidateA.strippedURL;
- var urlB = candidateB.strippedURL;
-
- if (urlA < urlB) // place A before B
- return -1;
- else if (urlA > urlB)
- return 1;
- // sort http://xyz.com before http://www.xyz.com
- else if (candidateA.URL.length < candidateB.URL.length)
- return -1;
- else if (candidateA.URL.length > candidateB.URL.length)
- return 1;
- else
- return 0;
- }
-